﻿using System;
using System.Activities.Presentation;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Headsight.BPMN2WF.BPMN;
using Headsight.BPMN2WF.BPMN.Schemas;
using Headsight.BPMN2WF.Transformation;
using Headsight.BPMN2WF.Transformation.BPMN2TransformerMappings.Config;

namespace Headsight.BPMN2WF.Console
{
    class BPMN2WF
    {
        [STAThread]
        static void Main(string[] args)
        {
            var cmdLineArgs = new Arguments(args);

            if (!ArgumentsOk(cmdLineArgs))
            {
                System.Console.WriteLine("Usage: BPMN2WF -s:BPMNSourceFile -d:XamlDestinationFile [-simplify] -converter:[SIMPLE|ADVANCED|CONFIG] [-mapping:Mapping-File]");
                return;
            }

            try
            {
                string bpmnFileContent;

                var source = cmdLineArgs["s"];
                var destination = cmdLineArgs["d"];
                var converter = cmdLineArgs["converter"];
                var simplify = cmdLineArgs["simplify"] != null;
                var mappingFile = cmdLineArgs["mapping"];

                System.Console.WriteLine("Executing BPMN2WF");
                System.Console.WriteLine("  - Source File: [{0}]", source);
                System.Console.WriteLine("  - Destination: [{0}]", destination);
                System.Console.WriteLine("  - Simplify   : [{0}]", simplify);
                System.Console.WriteLine("  - Converter  : [{0}]", converter);
                if (converter == "CONFIG")
                    System.Console.WriteLine("  - Mapping    : [{0}]", mappingFile);

                using (var streamReader = File.OpenText(source))
                    bpmnFileContent = streamReader.ReadToEnd();
                Convert(bpmnFileContent, destination, simplify, converter, mappingFile);
                System.Console.WriteLine("BPMN2WF - Ready");
            }
            catch (Exception ex)
            {
                System.Console.WriteLine(ex);
            }
        }

        private static bool ArgumentsOk(Arguments cmdLineArgs)
        {
            if (cmdLineArgs["s"] == null)
                return ArgumentError("Please specify BPMN Source-File");
            if (cmdLineArgs["d"] == null)
                return ArgumentError("Please specify XAML Destination-File");
            if (cmdLineArgs["converter"] == null)
                return ArgumentError("Please specify desired Converter. Choose either 'SIMPLE', 'ADVANCED' or 'CONFIG'");
            if (cmdLineArgs["converter"] != null)
            {
                if (cmdLineArgs["converter"] != "SIMPLE" && cmdLineArgs["converter"] != "ADVANCED" && cmdLineArgs["converter"] != "CONFIG")
                    return ArgumentError("Invalid Converter. Please Choose either 'SIMPLE', 'ADVANCED' or 'CONFIG'");
                if (cmdLineArgs["converter"] == "CONFIG")
                {
                    if (cmdLineArgs["mapping"] == null)
                        return ArgumentError("Please specify mapping file for conversion method 'CONFIG'.");
                }
            }

            return true;
        }

        private static bool ArgumentError(string errorMessage)
        {
            System.Console.WriteLine(errorMessage);
            return false;
        }

        private static IBPMN2WFTransformations CreateTransformator(string converter, string mappingFile)
        {
            if (converter == "CONFIG")
            {
                var argTypes = new[] { typeof(XmlDocument) };
                var constructor = typeof(BPMN2WFTransformationConfig).GetConstructor(argTypes);
                var mapping = new XmlDocument();
                mapping.LoadXml(mappingFile);
                var argValues = new[] { mapping };
                return (IBPMN2WFTransformations)constructor.Invoke(argValues);
            }

            var convName = string.Empty;
            if (converter == "SIMPLE")
                convName = "Headsight.BPMN2WF.Transformation.BPMN2TransformerMappings.BPMN2WFTransformationsSimple";
            if (converter == "ADVANCED")
                convName = "Headsight.BPMN2WF.Transformation.BPMN2TransformerMappings.BPMN2WFTransformationVNext";
            
            var type = AppDomain.CurrentDomain.GetAssemblies()
                          .SelectMany(a => a.GetTypes())
                          .FirstOrDefault(t => t.FullName == convName);
            return (IBPMN2WFTransformations)Activator.CreateInstance(type);
        }


        private static WorkflowDesigner Convert(string fileContent, string destinationFile, bool simplify, string converter, string mappingFile)
        {
            var encoding = new ASCIIEncoding();
            var bytes = encoding.GetBytes(fileContent);

            var ser = new XmlSerializer(typeof(tDefinitions));
            var tDefinition = (tDefinitions)ser.Deserialize(new MemoryStream(bytes));

            var bpmn2Wf = BPMN2WFFactory.Create(CreateTransformator(converter, mappingFile), simplify, tDefinition);
            var tDefinitions2BPMNFlowNodesBlock = new BPMNFlowNodesBlockFactory();

            var bpmnFlowNodesBlock = tDefinitions2BPMNFlowNodesBlock.CreateBPMNFlowNodesBlock(tDefinition);
            var result = bpmn2Wf.Transform(bpmnFlowNodesBlock);

            var wfDesigner = (WorkflowDesigner)result.Model;

            wfDesigner.Save(destinationFile);

            //var wfBeautifier = new WFBeautifier(wfDesigner);
            //wfDesigner = wfBeautifier.Beautify();

            return wfDesigner;
        }
    }
}
